home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / kernel / proc.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  19KB  |  587 lines

  1. /* This file contains essentially all of the process and message handling.
  2.  * It has two main entry points from the outside:
  3.  *
  4.  *   sys_call:   called when a process or task does SEND, RECEIVE or SENDREC
  5.  *   interrupt:    called by interrupt routines to send a message to task
  6.  *
  7.  * It also has several minor entry points:
  8.  *
  9.  *   lock_ready:      put a process on one of the ready queues so it can be run
  10.  *   lock_unready:    remove a process from the ready queues
  11.  *   lock_sched:      a process has run too long; schedule another one
  12.  *   lock_mini_send:  send a message (used by interrupt signals, etc.)
  13.  *   lock_pick_proc:  pick a process to run (used by system initialization)
  14.  *   unhold:          repeat all held-up interrupts
  15.  */
  16.  
  17. #include "kernel.h"
  18. #include <minix/callnr.h>
  19. #include <minix/com.h>
  20. #include "proc.h"
  21.  
  22. PRIVATE unsigned char switching;    /* nonzero to inhibit interrupt() */
  23.  
  24. FORWARD int mini_send();
  25. FORWARD int mini_rec();
  26. FORWARD void pick_proc();
  27. FORWARD void ready();
  28. FORWARD void sched();
  29. FORWARD void unready();
  30.  
  31. #if (CHIP == INTEL)
  32. #define CopyMess(s,sp,sm,dp,dm) \
  33.     cp_mess(s,(sp)->p_map[D].mem_phys,sm,(dp)->p_map[D].mem_phys,dm)
  34. #endif
  35. #if (CHIP == M68000)
  36. #define CopyMess(s,sp,sm,dp,dm) \
  37.     cp_mess(s,sp,sm,dp,dm)
  38. #endif
  39.  
  40. /*===========================================================================*
  41.  *                interrupt                     * 
  42.  *===========================================================================*/
  43. PUBLIC void interrupt(task)
  44. int task;            /* number of task to be started */
  45. {
  46. /* An interrupt has occurred.  Schedule the task that handles it. */
  47.  
  48.   register struct proc *rp;    /* pointer to task's proc entry */
  49.  
  50.   rp = proc_addr(task);
  51.  
  52.   /* If this call would compete with other process-switching functions, put
  53.    * it on the 'held' queue to be flushed at the next non-competing restart().
  54.    * The competing conditions are:
  55.    * (1) k_reenter == (typeof k_reenter) -1:
  56.    *     Call from the task level, typically from an output interrupt
  57.    *     routine.  An interrupt handler might reenter interrupt().  Rare,
  58.    *     so not worth special treatment.
  59.    * (2) k_reenter > 0:
  60.    *     Call from a nested interrupt handler.  A previous interrupt handler
  61.    *     might be inside interrupt() or sys_call().
  62.    * (3) switching != 0:
  63.    *     Some process-switching function other than interrupt() is being
  64.    *     called from the task level, typically sched() from CLOCK.  An
  65.    *     interrupt handler might call interrupt and pass the k_reenter test.
  66.    */
  67.   if (k_reenter != 0 || switching) {
  68.     lock();
  69.     if (!rp->p_int_held) {
  70.         rp->p_int_held = TRUE;
  71.         if (held_head != NIL_PROC)
  72.             held_tail->p_nextheld = rp;
  73.         else
  74.             held_head = rp;
  75.         held_tail = rp;
  76.         rp->p_nextheld = NIL_PROC;
  77.     }
  78.     unlock();
  79.     return;
  80.   }
  81.  
  82.   /* If task is not waiting for an interrupt, record the blockage. */
  83.   if ( (rp->p_flags & (RECEIVING | SENDING)) != RECEIVING ||
  84.       !isrxhardware(rp->p_getfrom)) {
  85.     rp->p_int_blocked = TRUE;
  86.     return;
  87.   }
  88.  
  89.   /* Destination is waiting for an interrupt.
  90.    * Send it a message with source HARDWARE and type HARD_INT.
  91.    * No more information can be reliably provided since interrupt messages
  92.    * are not queued.
  93.    */
  94.   rp->p_messbuf->m_source = HARDWARE;
  95.   rp->p_messbuf->m_type = HARD_INT;
  96.   rp->p_flags &= ~RECEIVING;
  97.   rp->p_int_blocked = FALSE;
  98.  
  99.    /* Make rp ready and run it unless a task is already running.  This is
  100.     * ready(rp) in-line for speed.
  101.     */
  102.   if (rdy_head[TASK_Q] != NIL_PROC)
  103.     rdy_tail[TASK_Q]->p_nextready = rp;
  104.   else
  105. #if (CHIP != M68000)
  106.     proc_ptr =
  107. #endif
  108.     rdy_head[TASK_Q] = rp;
  109.   rdy_tail[TASK_Q] = rp;
  110.   rp->p_nextready = NIL_PROC;
  111. }
  112.  
  113.  
  114. /*===========================================================================*
  115.  *                sys_call                     * 
  116.  *===========================================================================*/
  117. PUBLIC int sys_call(function, src_dest, m_ptr)
  118. int function;            /* SEND, RECEIVE, or BOTH */
  119. int src_dest;            /* source to receive from or dest to send to */
  120. message *m_ptr;            /* pointer to message */
  121. {
  122. /* The only system calls that exist in MINIX are sending and receiving
  123.  * messages.  These are done by trapping to the kernel with an INT instruction.
  124.  * The trap is caught and sys_call() is called to send or receive a message
  125.  * (or both). The caller is always given by proc_ptr.
  126.  */
  127.  
  128.   register struct proc *rp;
  129.   int n;
  130.  
  131.   /* Check for bad system call parameters. */
  132.   if (!isoksrc_dest(src_dest)) return(E_BAD_SRC);
  133.   rp = proc_ptr;
  134.   if (function != BOTH && isuserp(rp))
  135.     return(E_NO_PERM);    /* users only do BOTH */
  136.  
  137.   /* The parameters are ok. Do the call. */
  138.   if (function & SEND) {
  139.     /* Function = SEND or BOTH. */
  140.     n = mini_send(rp, src_dest, m_ptr);
  141.     if (function == SEND || n != OK)
  142.         return(n);    /* done, or SEND failed */
  143.   }
  144.  
  145.   /* Function = RECEIVE or BOTH.
  146.    * We have checked user calls are BOTH, and trust 'function' otherwise.
  147.    */
  148.   return(mini_rec(rp, src_dest, m_ptr));
  149. }
  150.  
  151.  
  152. /*===========================================================================*
  153.  *                mini_send                     * 
  154.  *===========================================================================*/
  155. PRIVATE int mini_send(caller_ptr, dest, m_ptr)
  156. register struct proc *caller_ptr;    /* who is trying to send a message? */
  157. int dest;            /* to whom is message being sent? */
  158. message *m_ptr;            /* pointer to message buffer */
  159. {
  160. /* Send a message from 'caller_ptr' to 'dest'. If 'dest' is blocked waiting
  161.  * for this message, copy the message to it and unblock 'dest'. If 'dest' is
  162.  * not waiting at all, or is waiting for another source, queue 'caller_ptr'.
  163.  */
  164.  
  165.   register struct proc *dest_ptr, *next_ptr;
  166.   vir_bytes vb;            /* message buffer pointer as vir_bytes */
  167.   vir_clicks vlo, vhi;        /* virtual clicks containing message to send */
  168.  
  169.   /* User processes are only allowed to send to FS and MM.  Check for this. */
  170.   if (isuserp(caller_ptr) && !isservn(dest)) return(E_BAD_DEST);
  171.   dest_ptr = proc_addr(dest);    /* pointer to destination's proc entry */
  172.   if (dest_ptr->p_flags & P_SLOT_FREE) return(E_BAD_DEST);    /* dead dest */
  173.  
  174.   /* Check for messages wrapping around top of memory or outside data seg. */
  175.   vb = (vir_bytes) m_ptr;
  176.   vlo = vb >> CLICK_SHIFT;    /* vir click for bottom of message */
  177.   vhi = (vb + MESS_SIZE - 1) >> CLICK_SHIFT;    /* vir click for top of msg */
  178.   if (vhi < vlo ||
  179.       vhi - caller_ptr->p_map[D].mem_vir >= caller_ptr->p_map[D].mem_len)
  180.     return(E_BAD_ADDR);
  181.  
  182.   /* Check for deadlock by 'caller_ptr' and 'dest' sending to each other. */
  183.   if (dest_ptr->p_flags & SENDING) {
  184.     next_ptr = caller_ptr->p_callerq;
  185.     while (next_ptr != NIL_PROC) {
  186.         if (next_ptr == dest_ptr) return(ELOCKED);
  187.         next_ptr = next_ptr->p_sendlink;
  188.     }
  189.   }
  190.  
  191.   /* Check to see if 'dest' is blocked waiting for this message. */
  192.   if ( (dest_ptr->p_flags & (RECEIVING | SENDING)) == RECEIVING &&
  193.        (dest_ptr->p_getfrom == ANY ||
  194.         dest_ptr->p_getfrom == proc_number(caller_ptr))) {
  195.     /* Destination is indeed waiting for this message. */
  196.     CopyMess(proc_number(caller_ptr), caller_ptr, m_ptr, dest_ptr,
  197.          dest_ptr->p_messbuf);
  198.     dest_ptr->p_flags &= ~RECEIVING;    /* deblock destination */
  199.     if (dest_ptr->p_flags == 0) ready(dest_ptr);
  200.   } else {
  201.     /* Destination is not waiting.  Block and queue caller. */
  202.     caller_ptr->p_messbuf = m_ptr;
  203.     if (caller_ptr->p_flags == 0) unready(caller_ptr);
  204.     caller_ptr->p_flags |= SENDING;
  205.  
  206.     /* Process is now blocked.  Put in on the destination's queue. */
  207.     if ( (next_ptr = dest_ptr->p_callerq) == NIL_PROC)
  208.         dest_ptr->p_callerq = caller_ptr;
  209.     else {
  210.         while (next_ptr->p_sendlink != NIL_PROC)
  211.             next_ptr = next_ptr->p_sendlink;
  212.         next_ptr->p_sendlink = caller_ptr;
  213.     }
  214.     caller_ptr->p_sendlink = NIL_PROC;
  215.   }
  216.   return(OK);
  217. }
  218.  
  219.  
  220. /*===========================================================================*
  221.  *                mini_rec                     * 
  222.  *===========================================================================*/
  223. PRIVATE int mini_rec(caller_ptr, src, m_ptr)
  224. register struct proc *caller_ptr;    /* process trying to get message */
  225. int src;            /* which message source is wanted (or ANY) */
  226. message *m_ptr;            /* pointer to message buffer */
  227. {
  228. /* A process or task wants to get a message.  If one is already queued,
  229.  * acquire it and deblock the sender.  If